/*
 * File Name: dht.h
 *
 * Last Modified: 18/4/12
 *
 * Author:          Marius Portmann - 2012
 * Modified By:     Steve Glass     - 2012
 *
 * Description:
 *      This header file provides all the definitions for the Distributed Hash
 *      table, high level API functions, Key-based routing functions and 
 *      finally debugging functions.
 *
 */

#ifndef DHT_H
#define DHT_H

#include <stddef.h>
#include <netinet/in.h>

#define KEY_SIZE 20				 /* 160 bit key space */
#define MAX_ENTRY_SIZE 4096    /* Max size of data objects in bytes */

struct node {
    in_addr_t ip_addr;   /* IP address of DHT node */
    in_port_t port;      /* port number of DHT node */
};

struct qParent {
    char q_IP[64];
    int q_port;
};

typedef uint8_t key[KEY_SIZE];  /* 160 bit node and object IDs or keys */

typedef struct node finger_table[KEY_SIZE * 8];

/********** HIGH LEVEL API **********/

int dht_put(struct node n, key k, const char buf[]);
/*
 * Functionality: 
 *      Stores a data object of size nbytes in the DHT, under the key k. The
 *      maximum size of data that the function accepts is DATA_BLOCK_SIZE,
 *      which is defined as 4096
 *
 * Parameters:
 *      n       : A node in the DHT
 *      buf     : Buffer containing the (NUL-terminated) data to be stored.
 *      k       : Object ID or key (128 bits) corresponding to the data 
 *                object (buf).
 * 
 * Returns:
 *      0 on success
 *      -1 on failure.
 */

int dht_remove(struct node n, key k);
/*
 * Functionality:
 *      Removes the data object corresponding to key k from the DHT.
 *
 * Parameters:
 *      n       : A node in the DHT
 *      k       : Object ID or key (128 bits) corresponding to the data object
 *
 * Returns:
 *      0 on success
 *      -1 on failure
 */

int dht_get(struct node n, key k, char buf[]);
/*
 * Functionality:
 *      Retrieves the data object corresponding to key k from the DHT, and
 *      stores it in the buffer buf. The function returns the size of the data
 *      object retrieved in bytes.  The function must guarantee that the 
 *      entire object is retrieved in one attempt, or else the function must
 *      return -1 (failure).  The caller of the function needs to make sure
 *      that buf is sufficiently large enough to hold DATA_BLOCK_SIZE bytes.
 *
 * Parameters:
 *      n       : A node in the DHT
 *      k       : Object ID or key (128 bits) of the data object to be 
 *                retrieved.
 *      buf     : Buffer where the returned data will be stored (must be
 *                at least MAX_ENTRY_SIZE+1 bytes long);
 * 
 * Returns:
 *      Number of bytes retrieved on success
 *      -1 on failure
 */

void dht_shutdown(struct node n);
/*
 * Parameters:
 *      n       : A node in the DHT
 * Functionality:
 *      Causes node n to gracefully leave the Chord ring and
 *      updates the finger tables of other nodes accordingly. This
 *      function must copy all of the data objects held by the node
 *      to the successor node in the ring. If this is the last
 *      remaining node then it may exit without copying any data.
 */

/********** KEY-BASED ROUTING FUNCTIONS **********/

int get_next_node(struct node *next_node_result, struct node *n, key k);
/*
 * Functionality:
 *      The function returns the next node, by filling out the node structure
 *      next_node_result.  The next node details are filled out according to 
 *      node n's finger table of the next node in the route to the final 
 *      destination node corresponding to key k.
 *
 *      This function can be called from any node, and therefore requires 
 *      communication with node n.  If the next hop returned by node n is node
 *      n, then we know that node n is the destination, i.e. the root node 
 *      responsible for key k.
 *      (This function can also provide the main functionality of the 
 *      iterative key-based routing mechanism.)
 *
 * Parameters:
 *      next_node_result    : The next node details returned by node n
 *      n                   : The node which is asked to perform the finger 
 *                            table lookup.
 *      k                   : Object ID or key (128 bits) of the data object 
 *                            to be located.
 *
 * Returns:
 *      0 on success
 *      -1 on failure
 */

int get_root_node(struct node *root_node, key k);
/*
 * Functionality:
 *      The functions returns the root node responsible of key k, i.e the
 *      immediate successor of key k, by filling out the node structure 
 *      root_node.  The function will typically make use of the get_next_node
 *      function.  This is equivalent to the find_successor(id) function
 *      mentioned in the Chord paper.
 *
 * Parameters:
 *      root_node       : Details of the root node responsible for key k
 *      k               : Object ID or key (128 bits) of the data object to
 *                        be located.
 *
 * Returns:
 *      0 on success
 *      -1 on failure
 */

int get_immediate_successor_node(struct node *next_node_result);
/*
 * Functionality:
 *      The function returns the immediate successor of the node on which this function
 *      is called.
 *
 * Parameters:
 *      next_node_result    : immediate successor node.
 *
 * Returns:
 *      0 on success
 *      -1 on failure
 */

/********** DEBUGGING FUNCTIONS **********/

int get_finger_table_entry(struct node n, size_t i, struct node *finger_i);
/*
 * Functionality:
 *      The function returns the i^th finger table entry of node n. The elements
 *      of the stored in each array element corresponds tothe array index
 *      i (0, ..., 159) as follows: 
 *      ft[i] = successor(Node ID of node n + 2^(i-1))
 *
 * Parameters:
 *      n        : node from which finger table is to be retrieved
 *      i        : index of the finger table entry to retrieve
 *      finger_i : pointer to a node where the n's i^th finger table entry will
 *                 be written
 *
 * Returns:
 *      0 on success
 *      -1 on failure
 */

int get_object_id(struct node n, size_t i, key *k);
/*
 * Functionality:
 *      The function returns the i^th key stored by node n. To retrieve multiple (or all) objects, 
 *      this function needs to be called multiple times. This is obviously not very efficient, 
 *      but keeps things relatively simple.
 *
 * Parameters:
 *      n       : Node from which the keys are being retrieved.
 *      k       : pointer to a key where the node n's i^th key will be written.
 *
 * Returns:
 *      The total number of keys held by the node on success
 *      -1 on failure
 */

int ping_node(struct node n);
/*
 * Functionality:
 *      This function determines if node n is alive, this function can be 
 *      called on any node.
 *
 * Parameters:
 *      n       : node to be pinged
 * 
 * Returns:
 *      0 if node responded successfully, negative error code on failure
 */

#endif
